#include <iostream>
#include <string>
#include <gmp.h>
#include <gmpxx.h>
#include <string>
#include <fstream>
#include <sstream>
#include <pthread.h>

#define BITS_PER_DIGIT 3.32192809488736234787;

// Variaveis globais
mpf_class *a0, *a1, *b0, *b1, *t0, *t1, *p0, *p1, *pi0, *pi1;

int cmpr;
int iteration;

void * threadP1 (void * noa) {
	*p1 = 2 * *p0;
	return 0;
}

void * threadA1 (void* noa) {
	*a1 = (*a0 + *b0) / 2;
	return 0;
}

void * threadB1 (void* noa) {
	*b1 = sqrt(*a0 * *b0);
	return 0;
}

void * threadWriter (void* noa) {
	std::stringstream ss;
	ss << "GLM_PI_It_" << iteration << ".txt";
	std::fstream file;
	file.open(ss.str().c_str(), std::fstream::out);
	file.setf(std::ios::fixed, std::ios::floatfield);
	file.precision(10000000);
	file << *pi0 << std::endl;
	return 0;
}

void gauss_legendre() {
	mpf_class eq_cmp;
	mpf_class tmp;
	eq_cmp = mpf_class("1E-10000000");
	iteration = 0;

	a0 = new mpf_class(1);
	b0 = new mpf_class(2);
	*b0 = sqrt(*a0 / *b0);
	t0 = new mpf_class(0.25);
	p0 = new mpf_class(1);

	a1 = new mpf_class();
	b1 = new mpf_class();
	t1 = new mpf_class();
	p1 = new mpf_class();

	pi0 = new mpf_class();
	pi1 = new mpf_class();

	tmp = *a0 + *b0;
	*pi0 = (tmp * tmp) / (4. * *t0);


	do {		

		pthread_t threadWriter_t;
		pthread_t threadA1_t;
		pthread_t threadB1_t;
		pthread_t threadP1_t;

		// pthread_create(&threadWriter_t, 0, threadWriter, 0);


		std::cout << "Comecando a calcular a iteracao " << ++iteration << std::endl;

		pthread_create(&threadP1_t, 0, threadP1, 0);

		pthread_create(&threadA1_t, 0, threadA1, 0);

		pthread_create(&threadB1_t, 0, threadB1, 0);		

		pthread_join(threadA1_t, 0);


		tmp = *a0 - *a1;
		*t1 = *t0 - *p0 * (tmp * tmp);

		

		pthread_join(threadB1_t, 0);

		tmp = *a1 + *b1;
		*pi1 = (tmp * tmp) / (4 * *t1);

		cmpr = cmp(abs(*pi1 - *pi0), eq_cmp);

		std::swap(a0, a1);
		std::swap(b0, b1);
		std::swap(t0, t1);

		pthread_join(threadP1_t, 0);
		std::swap(p0, p1);

		// pthread_join(threadWriter_t, 0);
		std::swap(pi0, pi1);

		{
			std::stringstream ss;
			ss << "GLMT_Iteracao_" << iteration << ".txt";
			std::fstream file;
			file.open(ss.str().c_str(), std::fstream::out);
			file.setf(std::ios::fixed, std::ios::floatfield);
			file.precision(10000000);
			file << *pi0 << std::endl;
		}


	} while (cmpr >= 0);

	
	std::cout << "PI calculado com sucesso em " << iteration << " iteracoes\n";

	delete a0;
	delete a1;
	delete b0;
	delete b1;
	delete t0;
	delete t1;
	delete p0;
	delete p1;
	delete pi0;
	delete pi1;
}

int main(int argc, char *argv[]) {
	mpf_set_default_prec((long int)(3.32192809488736234787 * 10000100.0));

	std::cout << "Bem vindo ao programa que calcula o PI!\n";
	std::cout << "10 milhoes de casas do pi serao calculadas!\n";
	std::cout << "Arquivos de prefixo \"GLMT_\" serao criados\n";

	// std::cout.setf(std::ios::fixed, std::ios::floatfield);
	// std::cout.precision(10000000);

	gauss_legendre();
	return 0;
}
